#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>

//情况1：写端关闭，读端读完pipe内数据后退出，read返回0表示读到结尾
//发送十条mag关闭写入端，读取端一直读
void test1()
{
  int pipefd[2] = {0};
  //pipe 成功返回0 失败返回-1
  if (pipe(pipefd) != 0){
    perror("pipe failed\n");
    exit(1);
  }

  if (fork() == 0){
    //child 进程
    close(pipefd[0]); //关闭读取端
    int count = 0;
    const char* msg = "hello pipe\n";
    while (count++ < 10){
      write(pipefd[1], msg, strlen(msg)); // 向管道中打印十条信息
    }
    close(pipefd[1]);//关闭写入端
    printf("chile end\n");
    exit(0);
  }
  //father 进程
  close(pipefd[1]); //关闭写入端
  while (1){
    sleep(1);
    char buffer[64] = {0};   
    size_t s = read(pipefd[0], buffer, sizeof(buffer) - 1); //将文件读取到buffer中并打印,一次读取s个字节
    if (s == 0){
      printf("file end\n");
      break;
    }
    else if (s > 0){
      printf("child say: %s", buffer);
    }
    else {
      break; //程序出错
    }
  }
  int status = 0;
  waitpid(-1, &status, 0); //父进程夯等待子进程
  printf("child exit code = %d, exit single = %d\n", (status >> 8) & 0xff, status & 0x7f); //输出子进程的退出码和得到的信号
}
//现象：读取端虽然读的慢，但是将文件读完结束后退出


//读端关闭，写端收到SIGPIPE信号被杀死
//写端一直写，读端读了一下关闭了
void test2()
{
  int pipefd[2] = {0};
  //pipe 成功返回0 失败返回-1
  if (pipe(pipefd) != 0){
    perror("pipe failed\n");
    exit(1);
  }

  if (fork() == 0){
    //child 进程
    close(pipefd[0]); //关闭读取端
    int count = 0;
    const char* msg = "hello pipe\n";
    while (++count){
      sleep(1);
      write(pipefd[1], msg, strlen(msg));// 每个一秒向管道中输入一次msg 
    }
    printf("chile end\n");
    exit(0);
  }
  //father 进程
  close(pipefd[1]); //关闭写入端
  while (1){
    char buffer[64] = {0};   
    size_t s = read(pipefd[0], buffer, sizeof(buffer) - 1); //将文件读取到buffer中并打印,一次读取s个字节
    if (s == 0){
      printf("file end\n");
      break;
    }
    else if (s > 0){
      printf("child say: %s", buffer);
      close(pipefd[0]);//读一次后,关闭读端并退出循环
      break;
    }
    else {
      break; //程序出错
    }
  }
  int status = 0;
  waitpid(-1, &status, 0); //父进程夯等待子进程
  printf("child exit code = %d, exit single = %d\n", (status >> 8) & 0xff, status & 0x7f); //输出子进程的退出码和得到的信号
}
//现象：读端读一次退出后，写端（子进程）被13信号杀死


//情况3：写端写的慢，读端需要等写端
void test3()
{
  int pipefd[2] = {0};
  //pipe 成功返回0 失败返回-1
  if (pipe(pipefd) != 0){
    perror("pipe failed\n");
    exit(1);
  }

  if (fork() == 0){
    //child 进程
    close(pipefd[0]); //关闭读取端
    int count = 0;
    const char* msg = "hello pipe\n";
    while (++count){
      sleep(3);
      write(pipefd[1], msg, strlen(msg)); // 向管道中打印十条信息
    }
    close(pipefd[1]);//关闭写入端
    printf("chile end\n");
    exit(0);
  }
  //father 进程
  close(pipefd[1]); //关闭写入端
  while (1){
    char buffer[64] = {0};   
    //写端写的慢，读端进行读取操作也会进入等待
    size_t s = read(pipefd[0], buffer, sizeof(buffer) - 1); //将文件读取到buffer中并打印,一次读取s个字节 
    if (s == 0){
      printf("file end\n");
      break;
    }
    else if (s > 0){
      printf("child say: %s", buffer);
    }
    else {
      break; //程序出错
    }
  }
  int status = 0;
  waitpid(-1, &status, 0); //父进程夯等待子进程
  printf("child exit code = %d, exit single = %d\n", (status >> 8) & 0xff, status & 0x7f); //输出子进程的退出码和得到的信号
}

//情况4：读端读的慢，写端也需要等读端
void test4()
{
  int pipefd[2] = {0};
  //pipe 成功返回0 失败返回-1
  if (pipe(pipefd) != 0){
    perror("pipe failed\n");
    exit(1);
  }

  if (fork() == 0){
    //child 进程
    close(pipefd[0]); //关闭读取端
    int count = 0;
    const char* msg = "hello pipe\n";
    while (++count){
      write(pipefd[1], msg, strlen(msg));
      printf("%d\n", count);
    }
    printf("chile end\n");
    exit(0);
  }
  //father 进程
  close(pipefd[1]); //关闭写入端
  while (1){
    sleep(1);
    char buffer[64] = {0};   
    size_t s = read(pipefd[0], buffer, sizeof(buffer) - 1); //将文件读取到buffer中并打印,一次读取s个字节
    if (s == 0){
      printf("file end\n");
      break;
    }
    else if (s > 0){
      printf("child say: %s", buffer);
    }
    else {
      break; //程序出错
    }
  }
  int status = 0;
  waitpid(-1, &status, 0); //父进程夯等待子进程
  printf("child exit code = %d, exit single = %d\n", (status >> 8) & 0xff, status & 0x7f); //输出子进程的退出码和得到的信号
}

void test5()
{
  int pipefd[2] = {0};
  if (pipe(pipefd) != 0){
    perror("pipe failed\n");
    exit(1);
  }
  if (fork() == 0){
    //child 进程
    close(pipefd[0]);
    int count = 0;
    while (1){
      write(pipefd[1], "a", 1);
      count++;
      printf("%d\n", count);
    }
    exit(0);
  }
  //father 进程
  close(pipefd[1]);
  char buffer[4 * 1024 + 1] = {0};
  while (1){
    sleep(3);
    read(pipefd[0], buffer, sizeof(buffer) - 1);
  }
  waitpid(-1, NULL, 0);

}
int main()
{
  //test1();
  //test2();
  //test3();
  //test4();
  test5();
  return 0;
}
